#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include "configfile.h"
#include "ssl.h"
#include "ecmfs_api.h"

/*
typedef struct client_info_ {
    char user_login[32];
    char user_password[32];
    EVP_Key   *my_key;
    EVP_Key   *my_pub_key;
    EVP_Key   *my_priv_key;
    char config_file_path[256];
} client_info_t;

typedef struct master_info_ {
    char master_ip[32];
    short int port;
    EVP_Key   *master_pub_key;
} master_info_t;

typedef struct edge_info_t {
    char edge_ip[32];
    short int port;
    EVP_Key   *edge_pub_key;
} edge_info_t;
client_info_t client;
master_info_t master;
edge_info_t   edge;
*/

typedef struct filegroup_info_t {
    char fileGrpName[256];
    char *read_user_list[32];
    char *write_user_list[32];
    char *file_name_list[32];
} filegroup_info_t;

typedef struct session_info_ {
    char mount_path[256];
    session_aes_key_t sessInfo;
    char *session_key;
    int session_key_len;
    filegroup_info_t *fgrpList;
    int fgrpListCount;
} session_info_t;


char *ecmfs_path;

session_info_t sessions;
config_file_t *cfile;
ssl_t ecmfs_ssl;
int is_ready_to_mount=0;
#define DEBUG 1

#if DEBUG
#define DEBUG_LOG(fmt , args...) \
    printf("\n[%s][%d] " fmt "\n" , __FUNCTION__, __LINE__ , ##args );
#else
#define DEBUG_LOG(fmt , args... ) 
#endif
void usage(char * prog)
{
    fprintf(stderr, "usage:%s <options> \n", prog);
    fprintf(stderr, "options:\n"
            "   --configfile   config file path (mandatory)\n"
            "   --password     password for key handling (mandatory)\n"
            "   --genkey       create new keypair and cert\n"
            "   --add_user     add_user\n"
            "   --mount        mount path\n");
}

int copy_user_public_key(char *FileName,  char *user_id,
                unsigned char *buffer, int *buffLen)
{
    FILE *fd;
    int i;
    char full_path[256];
    int c;
    
       
    if ((buffer == NULL) || (buffLen == 0)) {
         fprintf(stderr, 
            "%s null buffer\n", __FUNCTION__); 
         *buffLen = 0; 
        return -1;
    }
    if ((FileName == NULL ) || (user_id == NULL)){
         fprintf(stderr, 
            "%s null FileName\n", __FUNCTION__);
         *buffLen = 0; 
         return -1;
    }

    memset(full_path, 0, 256);
    strncpy(full_path, ecmfs_ssl.keyStorePath, 256);
    c = strlen(full_path);
    strncat(full_path, "/", (256-c)?(256-c):0);
    c = strlen(full_path);
    strncat(full_path, FileName, (256-c)?(256-c):0); 
    fprintf(stderr, 
       "%s FileName=%s\n", __FUNCTION__,full_path);     
    
    fd = fopen(full_path, "r");
    if (NULL == fd)
    {
         fprintf(stderr, 
            "%s Cannot open %s\n", __FUNCTION__,full_path);       
        *buffLen = 0; 
        return -1;
    }
    i = 0;
    if (feof(fd)) {
        fprintf(stderr, 
        "%s End of file reached %s\n", __FUNCTION__,full_path);  
        *buffLen = 0;
        return -1;
    }
    memset(buffer, 0, *buffLen);
    while (!feof(fd)) {
        char ch;
        if (i >= (*buffLen-1)) {
            fprintf(stderr, 
            "%s File too big %s\n", __FUNCTION__,full_path);
            *buffLen = 0;
            break;
        }
        ch = fgetc(fd);
        if (feof(fd)) {
            fprintf(stderr, 
            "%s End Of File %s\n", __FUNCTION__,full_path);             
            break;
        }
        buffer[i] = ch;
        i++;
    }
    fclose(fd);
    if (  *buffLen )  
    *buffLen = i;
     fprintf(stderr, 
        "%s Copied  %d bytes to buffer\n", __FUNCTION__,*buffLen);     
    return 1;
}
static void dump_ecmfs_message(ecmfs_message_t *msg)
{
   printf("magic_num=%d\n", msg->magic_num);
   printf("to=%d\n", msg->to);
   printf("from=%d\n", msg->from); 
   printf("type=%d\n",msg->type);
   printf("message_len=%d\n",msg->message_len);
}

int parse_arguments(int argc, char** argv)
{
    int ch, option_index=0;
    const char argstr[]="c:p:g:a:m:h";
    int config_file_read=0;
    int password_read=0; 
    int keys_read=0; 
    int keystore_init=0; 
    int msglen;
    int sd;
    int more;
    int add_request=0;
    

    
    static struct option long_options[] = {
        {"configfile", required_argument, 0, 'c'},        
        {"password", required_argument, 0, 'p'},
        {"genkey", no_argument, 0, 'g'},
        {"add_user", no_argument, 0, 'a'},        
        {"mount", required_argument, 0, 'm'},
        {"help", no_argument, 0, 'h'},
        {0,0,0,0}
    };

    if (argc < 2) {
         usage(argv[0]);
         return -1;
    }

    while ((ch=getopt_long(argc, argv, argstr, 
                    long_options, &option_index)) != -1) {
        switch (ch) {
        case 'c' : {
            if (optarg)
                printf("config fle=%s\n", optarg); 
            cfile = (config_file_t *) malloc(sizeof(config_file_t));
            config_file_init(cfile,  optarg);
            cfg_ropen(cfile, optarg);
            cfg_read_file(cfile);
            cfg_close(cfile);
            ecmfs_path = cfile->keystore_path;
            config_file_read=1;
            break;
        } 
        case 'p' : {
            if (config_file_read == 0) {
                fprintf(stderr, 
                    "please provide config file first");
                return -1;
            }                
            if (optarg) {
                strncpy(cfile->password, optarg, 32);
            }                
            password_read=1;
            break;
        }         
        case 'g' : {
            char keyStorePath[256];
            ssl_ret_t ret1, ret2;
            struct stat st = {0};
            int c;
 
            if ((config_file_read == 0) ||
                (password_read == 0))
            {
                fprintf(stderr, 
                    "please provide config file and password first");
                return -1;
            }
            
            init_ssl(); 
            /* certificate and keys for master */
            /* create keystore */
            memset(keyStorePath, 0, sizeof(keyStorePath));
            strncpy(keyStorePath, ecmfs_path, 256);
            c = strlen(keyStorePath);
            if (stat(keyStorePath, &st) == -1) {
                printf("%s does not exist:"
                    "creating a dir\n", ecmfs_path);
                mkdir(keyStorePath, 0700);
            } 
            strncat(keyStorePath, "/",(256-c)?(256-c):0);
    
            if (stat(keyStorePath, &st) == -1) {
                printf("%s does not exist in %s;"
                    "creating a dir\n", cfile->user_id,ecmfs_path);
                mkdir(keyStorePath, 0700);
            } 
            
            /* create node encryption and
               sign keys */ 
            set_keyStore_path(&ecmfs_ssl, 
                keyStorePath);
            set_root_ca_cert(&ecmfs_ssl,
                (char *) "ca_cert.pem");
            keystore_init = 1;
            create_my_encryption_keys(&ecmfs_ssl, 
                (char *)"my_enc_pub.pem",
                (char *)"my_enc_priv.pem", 
                (char *) cfile->password);
            create_my_signing_keys(&ecmfs_ssl, 
                (char *)"my_sign_pub.pem",
                (char *)"my_sign_priv.pem",
                (char *) cfile->password);
    
            create_my_cert(&ecmfs_ssl,
                (char *)"my_cert.pem");
            ret1 = read_my_encryption_keys(&ecmfs_ssl, 
                (char *)"my_enc_pub.pem",
                (char *)"my_enc_priv.pem", 
                (char *)cfile->password);
            ret2 = read_my_signing_keys(&ecmfs_ssl, 
                (char *)"my_sign_pub.pem",
                (char *)"my_sign_priv.pem",
                (char *)cfile->password);
            if ((ret1 == SSL_SUCCESS) && 
                (ret2 == SSL_SUCCESS)){
                keys_read=1;
            }
            break;
        }
        case 'a':
        {
            add_request=1;
        }
        break;
        default:
        {
            usage(argv[0]);
            fprintf(stderr, "ignoring option character %c\n", optopt);
            return -1;
        }
    } /* switch */
    } /* while */
    
    if ((config_file_read == 0) ||
        (password_read == 0))
    {
        fprintf(stderr, 
            "please provide config file and password first");
        return -1;
    }    
    /* if keys are not read yet, read them now */
    if (!keys_read) {
        char keyStorePath[256];
        ssl_ret_t ret1, ret2;
        struct stat st = {0};
        int c;
        
        if (!keystore_init) {
            init_ssl(); 
            /* certificate and keys for master */
            /* create keystore */
            memset(keyStorePath, 0, sizeof(keyStorePath));
            strncpy(keyStorePath, ecmfs_path, 256);
            c = strlen(keyStorePath);
            if (stat(keyStorePath, &st) == -1) {
                printf("%s does not exist:"
                    "creating a dir\n", ecmfs_path);
                mkdir(keyStorePath, 0700);
            } 
            strncat(keyStorePath, "/",(256-c)?(256-c):0);
    
            if (stat(keyStorePath, &st) == -1) {
                printf("%s does not exist in %s;"
                    "creating a dir\n", cfile->user_id,ecmfs_path);
                mkdir(keyStorePath, 0700);
            } 
            
            /* create node encryption and
               sign keys */ 
            set_keyStore_path(&ecmfs_ssl, 
                keyStorePath);
            set_root_ca_cert(&ecmfs_ssl,
                (char *) "ca_cert.pem");
        }
        ret1 = read_my_encryption_keys(&ecmfs_ssl, 
            (char *)"my_enc_pub.pem",
            (char *)"my_enc_priv.pem", 
            (char *)cfile->password);
        ret2 = read_my_signing_keys(&ecmfs_ssl, 
            (char *)"my_sign_pub.pem",
            (char *)"my_sign_priv.pem",
            (char *)cfile->password);
        if ((ret1 == SSL_SUCCESS) && 
            (ret2 == SSL_SUCCESS)){
            keys_read=1;
        }
    }
    
    if (keys_read == 0) {
       fprintf(stderr, "user keys not available, not able to start\n");
       return -1;        
    }
   
    ecmfs_message_t *msg;
    ecmfs_add_user_t *add_user_msg;
    unsigned char *response_buffer;
    int response_length;
        
    if  (add_request == 1) {
        /* Add User */
        /* Note this has to be done in a secure channel
           Perhaps an SSL connection
           Not done as part of the project 
         */

    
        add_user_msg = (ecmfs_add_user_t *)
                    malloc(sizeof(ecmfs_add_user_t));
        if (!add_user_msg) {
           fprintf(stderr, "no memory for add_user_msg\n");
            return -1;
        }        
        memset(add_user_msg, 0, sizeof(ecmfs_add_user_t));
        strncpy(add_user_msg->user_id, cfile->user_id, 32);
        add_user_msg->user_pub_key_len = MAX_PUB_KEY_LEN;
        copy_user_public_key("my_enc_pub.pem",add_user_msg->user_id,
                            add_user_msg->user_pub_key,
                            &(add_user_msg->user_pub_key_len));
        fprintf(stderr, "Public key copied %d bytes\n",
                add_user_msg->user_pub_key_len);                
        msglen = sizeof(ecmfs_message_t)+
                    sizeof(ecmfs_add_user_t);
        fprintf(stderr, "Allocating %d bytes for ecmfs_message_t\n",msglen);                
        msg = (ecmfs_message_t *) malloc(msglen);
        if (!msg) {
           fprintf(stderr, "no memory for ecmfs_message_t\n");
           free(add_user_msg);
           return -1;
        }    
        memset(msg,0, msglen);
        msg->magic_num = MAGIC_NUM;
        msg->from = NODE_CLIENT;
        msg->to = NODE_MASTER;
        msg->type = CLIENT_OP_ADDUSER;
        msg->message_len = sizeof(add_user_msg->user_id) +
                            sizeof(add_user_msg->user_pub_key_len) +
                        add_user_msg->user_pub_key_len;
        msglen = sizeof(ecmfs_message_t) +  msg->message_len - 1;
        printf("Sending %d bytes of message to master\n", msglen); 
        memcpy(msg->message, add_user_msg, msglen);
        sd = client_send_message_to_master(msg, ECMFS_FALSE);        
    } else {
        /* Say Hello,Once server acknowledges without
           additional requests,we are good to go.
        */

        add_user_msg = (ecmfs_add_user_t *) 
                malloc(sizeof(ecmfs_add_user_t));
        if (!add_user_msg) {
           fprintf(stderr, "no memory for add_user_msg\n");
            return -1;
        }        
        memset(add_user_msg, 0, sizeof(ecmfs_add_user_t));
        strncpy(add_user_msg->user_id, cfile->user_id, 32);
        add_user_msg->user_pub_key_len = 0;
        msglen = sizeof(ecmfs_message_t)+
                sizeof(ecmfs_add_user_t);
        fprintf(stderr, "Allocating %d bytes for ecmfs_message_t\n",msglen);                
        msg = (ecmfs_message_t *) malloc(msglen);
        if (!msg) {
           fprintf(stderr, "no memory for ecmfs_message_t\n");
           free(add_user_msg);
           return -1;
        }    
        memset(msg,0, msglen);
        msg->magic_num = MAGIC_NUM;
        msg->from = NODE_CLIENT;
        msg->to = NODE_MASTER;
        msg->type = CLIENT_OP_HELLO;
        msg->message_len = sizeof(add_user_msg->user_id) +
                            sizeof(add_user_msg->user_pub_key_len) +
                        add_user_msg->user_pub_key_len;
        msglen = sizeof(ecmfs_message_t) +  msg->message_len - 1;
        printf("Sending %d bytes of message to master\n", msglen); 
        memcpy(msg->message, add_user_msg, msglen);
        sd = client_send_message_to_master(msg, ECMFS_FALSE); 
    }

    
    more = 0;
    do {
        receive_server_response(sd, &response_buffer,
                            &response_length);
 
        client_handle_message(response_buffer, 
                            response_length, &more);
        free(response_buffer);
        response_buffer=NULL;
        response_length=0;
    }
    while(more);
    
    free(add_user_msg);
    free(msg);
    add_user_msg = NULL;
    msg = NULL;
    
    if (is_ready_to_mount) {
        printf("Starting the mount session..\n");         
        start_mount_session(argc, argv);
    }
    return 0;
}



#define MASTER_NODE "master1"
#define EDGE_NODE   "edge1"

int send_ecmfs_request(client_op_t opcode, void *arg)
{
    ecmfs_message_t *msg;
    ecmfs_add_user_t *add_user_msg;;
    int response_length;
    char *response_buffer;
    int msglen;
    int sd;
    int more;
    if (opcode == CLIENT_OP_MOUNT) {
        add_user_msg = (ecmfs_add_user_t *) 
                malloc(sizeof(ecmfs_add_user_t));
        if (!add_user_msg) {
           fprintf(stderr, "no memory for add_user_msg\n");
            return -1;
        }        
        memset(add_user_msg, 0, sizeof(ecmfs_add_user_t));
        strncpy(add_user_msg->user_id, cfile->user_id, 32);
        add_user_msg->user_pub_key_len = 0;
        msglen = sizeof(ecmfs_message_t)+
                sizeof(ecmfs_add_user_t);
        fprintf(stderr, "Allocating %d bytes for ecmfs_message_t\n",msglen);                
        msg = (ecmfs_message_t *) malloc(msglen);
        if (!msg) {
           fprintf(stderr, "no memory for ecmfs_message_t\n");
           free(add_user_msg);
           return -1;
        }    
        memset(msg,0, msglen);
        msg->magic_num = MAGIC_NUM;
        msg->from = NODE_CLIENT;
        msg->to = NODE_MASTER;
        msg->type = CLIENT_OP_MOUNT;
        msg->message_len = sizeof(add_user_msg->user_id) +
                            sizeof(add_user_msg->user_pub_key_len) +
                        add_user_msg->user_pub_key_len;
        msglen = sizeof(ecmfs_message_t) +  msg->message_len - 1;
        printf("Sending %d bytes of message to master\n", msglen); 
        memcpy(msg->message, add_user_msg, msglen);
        sd = client_send_message_to_master(msg, ECMFS_FALSE); 
    }

    
    more = 0;
    do {
        receive_server_response(sd, (unsigned char **)&response_buffer,
                            &response_length);
 
        client_handle_message((unsigned char *)response_buffer, 
                            response_length, &more);
        free(response_buffer);
        response_buffer=NULL;
        response_length=0;
    }
    while(more);
    

    if (opcode == CLIENT_OP_MOUNT) {
        free(msg);
        msg = NULL;
    }
    return 1;
}

int client_send_message_to_master(ecmfs_message_t *msg, bool_ecmfs encrypted)
{
    int sockfd, portno, n, writelen;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    int header_len, total_len;
    struct in_addr ipv4addr;    

    /* Create a socket point */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
    {
        fprintf(stderr, "ERROR opening socket %d(%s)",
                    errno, strerror(errno));
        return -1;
    }
    DEBUG_LOG("Server: %s\n", cfile->master_ip);
    dump_ecmfs_message(msg);
    
    
    inet_pton(AF_INET, cfile->master_ip, &ipv4addr);
    server = gethostbyaddr(&ipv4addr, sizeof(ipv4addr), AF_INET);    
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        return -1;
    }
    portno = cfile->master_port;

    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
           (char *)&serv_addr.sin_addr.s_addr,
                server->h_length);
    serv_addr.sin_port = htons(portno);

    /* connect to the server */
    if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) 
    {
        fprintf(stderr, "ERROR connecting %d(%s)",
                    errno, strerror(errno));
        return -1;
    }	
    header_len = 
    sizeof(msg->magic_num) + 
    sizeof(msg->from) +
    sizeof(msg->to) +
    sizeof(msg->type) + 
    sizeof(msg->extra) +     
    sizeof(msg->message_len);
    total_len = header_len + msg->message_len;
    
    /* Send message to the server */
     if (encrypted) {
         ssl_ret_t ret;
         char pub_key_file_name[100];
         EVP_PKEY *pPubKey;
         unsigned char* encode_buffer;
         int encode_bufsize;

         
         strcpy(pub_key_file_name,MASTER_NODE);
         strcat(pub_key_file_name,"_pub.key");
   
         ret = read_rsa_pub_key(&ecmfs_ssl, pub_key_file_name,&pPubKey);
         if (SSL_SUCCESS !=  ret) {
             fprintf(stderr, 
                 "Error in converting Pub key file to EVP_KEY\n");
             fprintf(stderr, "Freeing up %p\n",msg);        
             free(msg);                 
             return -1;
         }
         ret = encode_rsa_message(&ecmfs_ssl,pPubKey,
                    (unsigned char *)msg, total_len, 
                    &encode_buffer, &encode_bufsize);
         if (SSL_SUCCESS !=  ret) {
             fprintf(stderr, 
                 "Error in encoding\n");
             fprintf(stderr, "Freeing up %p\n",msg);
             /* also free up EVP Key */
                 EVP_PKEY_free(pPubKey);
             free(msg);                 
             return -1;
         }             
             
         if (msg) {
               fprintf(stderr, "Freeing up %p\n",msg);        
               free(msg);
         } 
         EVP_PKEY_free(pPubKey);
         msg = (ecmfs_message_t *) encode_buffer;
         total_len = encode_bufsize;
    } else {
        /* send sraight away in plain */
    }
    
    
    writelen = 0;
    do {
        DEBUG_LOG("Server: %s; total_len=%d, write_len=%d\n",
            cfile->master_ip,total_len,writelen);
        n = write(sockfd,((char *)msg )+ writelen,total_len-writelen);
        if (n < 0) 
        {
            fprintf(stderr, "ERROR writing to socket %d(%s)",
                        errno, strerror(errno));
            return -1;
        }
        writelen += n;
    } while(writelen < total_len);
    DEBUG_LOG("%s", "Writing to server done\n");    
    return sockfd;
}

int receive_server_response(int sockfd,unsigned char **buffer,
                            int *buff_len)
{
    int read_len, avail_len, max_len, min_len, step_len;
    int n;
    unsigned char *buff_start;
    unsigned char *buff;
    
    /* Now read server response */
    max_len = 4096;
    step_len = 1024;
    min_len = 256;
    buff_start = (unsigned char *) malloc(max_len);
    buff = buff_start;
    read_len = 0;
    avail_len = max_len;
    bzero(buff_start,max_len);

    //do {
        DEBUG_LOG("Waiting to read from server:\n");
        n = read(sockfd,buff,avail_len);
        if (n < 0) 
        {
             fprintf(stderr, "ERROR reading from socket %d(%s)", 
                 errno, strerror(errno));
            *buffer = buff_start;
            *buff_len = read_len;
            return 1;
        }

        read_len += n;
        avail_len -=n;
        DEBUG_LOG("read %d characters %d available to read\n",
            read_len,avail_len); 
        
        if (avail_len > min_len) {
            buff += n;
        } else {
            max_len+=step_len;
            avail_len+=step_len;
            buff_start = (unsigned char *)realloc(buff_start, max_len);
            buff = buff_start + read_len;
        }
        
    //} while(n > 0);
    *buffer = buff_start;
    *buff_len = read_len;
    DEBUG_LOG("read %d characters returning\n",read_len);
    return 1;
}

void client_handle_message(unsigned char *buffer, int bufsize, int *more)  
{
    unsigned char *decoded_buffer; 
    ecmfs_message_t *msg;
    int decoded_bufsize;
    *more=0;    
    if (bufsize < sizeof(ecmfs_message_t)) {
        fprintf (stderr, "Client: cannot handle this message\n");
        return;
    }
        
    msg = (ecmfs_message_t *) buffer;
    if (msg->magic_num == 19977991) {
      /* Can get clear text for initial
         user add. A TODO is to make that
         an SSL connection, where the master
         does not know the user's public key
         yet.
       */
      fprintf (stderr, "Client: got cleartext\n");
    } else {
      
      fprintf (stderr, "Client: got non ecmfs header check if encrypted\n");
      decode_rsa_message(&ecmfs_ssl, ecmfs_ssl.enc_priv_key, buffer, bufsize,
                    &decoded_buffer, &decoded_bufsize); 
      msg = (ecmfs_message_t *) decoded_buffer;
    }

    switch(msg->from) 
    {
     case NODE_CLIENT:
         client_handle_client_message(msg, more);
         break;
     case NODE_EDGE:
         client_handle_edge_message(msg, more);
         break;
     case NODE_CORE:
         client_handle_core_message(msg, more);
         break;
     case NODE_MASTER:
         client_handle_master_message(msg, more);
         break;
     default:
         break;
    }
}



bool_ecmfs client_handle_client_message(ecmfs_message_t *msg, int *more);
bool_ecmfs client_handle_edge_message(ecmfs_message_t *msg, int *more);
bool_ecmfs client_handle_core_message(ecmfs_message_t *msg, int *more);
bool_ecmfs client_handle_master_message(ecmfs_message_t *msg, int *more);


bool_ecmfs client_handle_client_message(ecmfs_message_t *msg, int *more)
{
    dump_ecmfs_message(msg);
    return ECMFS_TRUE;
}

bool_ecmfs client_handle_edge_message(ecmfs_message_t *msg, int *more)
{
    dump_ecmfs_message(msg);    
    return ECMFS_TRUE;
}
bool_ecmfs client_handle_core_message(ecmfs_message_t *msg, int *more)
{
    dump_ecmfs_message(msg);
    return ECMFS_TRUE;
}
int store_node_public_key(ecmfs_runtime_state_t *nodeState);

bool_ecmfs client_handle_master_message(ecmfs_message_t *msg, 
                                       int *more)
{
    dump_ecmfs_message(msg);
    switch(msg->type) 
    {
        case MASTER_OP_RESPONSE:
            {
                ecmfs_server_response_t *response;
                
                response = (ecmfs_server_response_t *)
                        msg->message;
                         
                switch(response->resp) 
                {
                    case SERVER_RESP_HELLO:
                        fprintf (stderr, "Server said hello\n");
                        break;
                    case SERVER_RESP_WHOAREYOU:
                        fprintf (stderr, 
                            "Please add user in a secure channel"
                            "Server does not know you\n");
                        return ECMFS_TRUE;
                    case SERVER_RESP_DONE:    
                        fprintf (stderr, 
                            "Server acknowledged your request\n");
                        if (response->more) {
                            fprintf (stderr, 
                                "There are more responses to follow");
                            *more = 1;
                        }
                        break;
                    case SERVER_RESP_ERROR:    
                        fprintf (stderr, 
                            "Server had an error\n");
                        return ECMFS_TRUE;                        
                    case SERVER_RESP_SENDING_PUBKEY:
                        {
                            ecmfs_runtime_state_t *serverState;
                            
                        fprintf (stderr, 
                            "Server is sending public keys");
                        serverState = (ecmfs_runtime_state_t *) response->msg;
                        store_node_public_key(serverState);
                        if (response->more) {
                            fprintf (stderr, 
                                "There are more responses to follow");
                            *more = 1;
                        }
                        }
                        break;
                    case SERVER_RESP_INTERNAL_ERROR:
                           fprintf (stderr, 
                            "Server had an internal error\n");
                        return ECMFS_TRUE;
                    case SERVER_RESP_MOUNT_OK:
                        {
                           fprintf (stderr, 
                            "Session details copied...\n");
                            
                            memcpy(
                               &sessions.sessInfo,
                               (session_aes_key_t *)response->msg, 
                               sizeof(session_aes_key_t));
                            return ECMFS_TRUE;
                        }
                    break;                        
                    case SERVER_RESP_UNKNOWN:
                    default:
                           fprintf (stderr, 
                            "Unknown response\n");
                        return ECMFS_TRUE;                         
                }
                fprintf (stderr, "Server state=%d\n", 
                            response->state);
                
                if (response->state != SERVER_STATE_READY)
                {
                   fprintf (stderr, "Server not ready for sessions, try mouonting again\n");
                   return ECMFS_TRUE;
                }
                if (*more == 0) {
                    is_ready_to_mount = 1;
                }
            }
        case MASTER_OP_NOTIFICATION:
        case MASTER_OP_USERUPDATE:
        case MASTER_OP_NODEUPDATE:
        case MASTER_OP_SESSIONUPDATE:
        case MASTER_OP_FAILOVER:
        default:
           fprintf (stderr, "Not yet handled\n");
           return ECMFS_TRUE;   
    }
    
    return ECMFS_TRUE;
}

int copy_from_file(char *buffer, int *buffer_len, char *file_name);
int copy_from_file(char *buffer, int *buffer_len, char *file_name)
{
    FILE *fd;
    int rlen;
    int total_read;
    char *iterBuff;
    char ch;
    fprintf(stderr, "%s: Opening %s\n", __FUNCTION__, file_name);
    fd = fopen(file_name, "r");
    if (!fd) {
        fprintf(stderr, "%s: Cannot open %s\n", __FUNCTION__, file_name);
        return -1;
    }

    rlen = 0;
    total_read = 0;
    iterBuff = buffer;
    do {
        ch = fgetc(fd);
        /*
        fread(buffer+rlen,
                    (*buffer_len - rlen),
                    1,
                    fd);
        */           
        if (ferror(fd)) {
            fprintf(stderr,"%s: error in reading\n", __FUNCTION__);
            break;
        }
        else {

            rlen++;
            
            if (rlen >= *buffer_len) {
                fprintf(stderr,"%s: read %d, buffer capacity %d\n",
                    __FUNCTION__, rlen,  *buffer_len);
                break;
            } else {
                total_read++;
                *iterBuff = ch;
                iterBuff++;
                if (feof(fd)) {
                    fprintf(stderr,"%s: read %d bytes, end of file\n",
                        __FUNCTION__, total_read);
                } else {
                    if (rlen % 128 == 0)
                    fprintf(stderr,
                        "%s: read %d bytes, reading more\n", 
                        __FUNCTION__, total_read);
                }
            }
        }  
    }while (!feof(fd));

    *buffer_len = (total_read - 1);
    
    if (!feof(fd)) {
        fprintf(stderr,"%s: read %d bytes, returning before eof\n", __FUNCTION__, total_read);
        fclose(fd);
        return -1;
    }
    fprintf(stderr,"%s: read %d bytes, returning after eof\n", __FUNCTION__, total_read);
    fclose(fd);    
    return 1;
}

int copy_to_file(char *buffer, int buffer_len, char *file_name);
int copy_to_file(char *buffer, int buffer_len, char *file_name)
{
    FILE *fd;
    int wlen;
    int total_written;
    char *iterBuff;
    char ch;
    fprintf(stderr, "%s: Opening %s\n", __FUNCTION__, file_name);
    fd = fopen(file_name, "w");
    if (!fd) {
        fprintf(stderr, "%s: Cannot open %s\n", __FUNCTION__, file_name);
        return -1;
    }

    wlen = 0;
    total_written = 0;
    iterBuff = buffer;
    do {
        if (wlen > buffer_len)
        {
            break;
        }
        ch = *iterBuff; 

       
        fputc(ch, fd);
        wlen++;
        if (ferror(fd)) {
            fprintf(stderr,"%s: error in reading\n", __FUNCTION__);
            break;
        }
        else {
                total_written++;
                iterBuff++;
                if (wlen % 128 == 0)
                    fprintf(stderr,
                        "%s: written %d bytes, writing more\n", 
                        __FUNCTION__, total_written);
        }
    }while (!feof(fd));

    fprintf(stderr,"%s: written %d bytes, returning after eof\n",
                                __FUNCTION__, total_written);
    
    fclose(fd);
    return 1;
}

void print_runtime_state(ecmfs_runtime_state_t *ecmfs);

void print_runtime_state(ecmfs_runtime_state_t *ecmfs)
{
    int i=0;
    printf("node state = %d\n", ecmfs->state);

    printf("node_name = %s\n", ecmfs->info.node_name);
    printf("node_type = %d\n", ecmfs->info.node_type);
    printf("node_ip = %s\n", ecmfs->info.node_ip);    
    printf("node_port = %d\n", ecmfs->info.node_port);
    printf("node_pub_key_len = %d\n", ecmfs->info.node_pub_key_len);
    
    
    printf("node_pub_key = \n");

    while (i <  ecmfs->info.node_pub_key_len) 
    {
        printf("%c", ecmfs->info.node_pub_key[i]);
        i++;
    }
}

int store_node_public_key(ecmfs_runtime_state_t *nodeState)
{
    char keyStorePath[256];
    int c;

    
    fprintf (stderr, "Node %s sending its public key\n",
        nodeState->info.node_name);
    
    memset(keyStorePath, 0, 
           sizeof(keyStorePath));
    strncpy(keyStorePath, cfile->keystore_path, 256);
    strcat(keyStorePath, "/");    
    c = strlen(keyStorePath);
    strncat(keyStorePath, cfile->user_id,(256-c)?(256-c):0);
    c = strlen(keyStorePath);
    strcat(keyStorePath, "/");    
    strncat(keyStorePath, nodeState->info.node_name,
                        (256-c)?(256-c):0); 
    strncat(keyStorePath, "_pub.key",
                    (256-c)?(256-c):0); 
    print_runtime_state(nodeState);
    copy_to_file((char *)nodeState->info.node_pub_key, 
                nodeState->info.node_pub_key_len,
                keyStorePath);
    return 0;
}

int main(int argc, char *argv[])
{
    int ret;
    
    ret = parse_arguments(argc, argv);
    return ret;
}
